package com.nju.edu.erp.service.sale;

import com.nju.edu.erp.dao.CustomerDao;
import com.nju.edu.erp.dao.ProductDao;
import com.nju.edu.erp.dao.SaleSheetDao;
import com.nju.edu.erp.enums.sheetState.SaleSheetState;
import com.nju.edu.erp.model.po.*;
import com.nju.edu.erp.model.vo.ProductInfoVO;
import com.nju.edu.erp.model.vo.Sale.SaleSheetContentVO;
import com.nju.edu.erp.model.vo.Sale.SaleSheetVO;
import com.nju.edu.erp.model.vo.UserVO;
import com.nju.edu.erp.model.vo.business.BusinessConditionVO;
import com.nju.edu.erp.model.vo.warehouse.WarehouseOutputFormContentVO;
import com.nju.edu.erp.model.vo.warehouse.WarehouseOutputFormVO;
import com.nju.edu.erp.service.customer.CustomerService;
import com.nju.edu.erp.service.wareHouse.ProductService;
import com.nju.edu.erp.service.wareHouse.WarehouseService;
import com.nju.edu.erp.utils.IdGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


@Service
public class SaleServiceImpl implements SaleService {

    private final SaleSheetDao saleSheetDao;

    private final ProductDao productDao;

    private final CustomerDao customerDao;

    private final ProductService productService;

    private final CustomerService customerService;

    private final WarehouseService warehouseService;

    @Autowired
    public SaleServiceImpl(SaleSheetDao saleSheetDao, ProductDao productDao, CustomerDao customerDao, ProductService productService, CustomerService customerService, WarehouseService warehouseService) {
        this.saleSheetDao = saleSheetDao;
        this.productDao = productDao;
        this.customerDao = customerDao;
        this.productService = productService;
        this.customerService = customerService;
        this.warehouseService = warehouseService;
    }

    @Override
    @Transactional
    public void makeSaleSheet(UserVO userVO, SaleSheetVO saleSheetVO) {
        // TODO
        // 需要持久化销售单（SaleSheet）和销售单content（SaleSheetContent），其中总价或者折后价格的计算需要在后端进行
        // 需要的service和dao层相关方法均已提供，可以不用自己再实现一遍
        SaleSheetPO saleSheetPO = new SaleSheetPO();
        BeanUtils.copyProperties(saleSheetVO, saleSheetPO);
        saleSheetPO.setSalesman(userVO.getName());
        saleSheetPO.setCreateTime(new Date());
        SaleSheetPO latest=saleSheetDao.getLatestSheet();
        String id=IdGenerator.generateSheetId(latest == null ? null : latest.getId(), "XSD");
        saleSheetPO.setId(id);
        saleSheetPO.setState(SaleSheetState.PENDING_LEVEL_1);
        BigDecimal totalAmount = BigDecimal.ZERO;
        List<SaleSheetContentPO> sContentPOList = new ArrayList<>();

        for(SaleSheetContentVO content : saleSheetVO.getSaleSheetContent()) {
            SaleSheetContentPO SaleContentPO = new SaleSheetContentPO();
            BeanUtils.copyProperties(content,SaleContentPO);
            SaleContentPO.setSaleSheetId(id);
            BigDecimal unitPrice = SaleContentPO.getUnitPrice();

            if(unitPrice == null) {
                ProductPO product = productDao.findById(content.getPid());
                unitPrice = product.getRetailPrice();
                SaleContentPO.setUnitPrice(unitPrice);
            }
            SaleContentPO.setTotalPrice(unitPrice.multiply(BigDecimal.valueOf(SaleContentPO.getQuantity())));
            sContentPOList.add(SaleContentPO);
            totalAmount = totalAmount.add(SaleContentPO.getTotalPrice());
        }
        saleSheetPO.setRawTotalAmount(totalAmount);
        saleSheetPO.setFinalAmount(totalAmount.multiply(saleSheetPO.getDiscount()).subtract(saleSheetPO.getVoucherAmount()));
        saleSheetDao.saveSheet(saleSheetPO);

        //持久化销售单content
        saleSheetDao.saveBatchSheetContent(sContentPOList);

    }

    @Override
    @Transactional
    public List<SaleSheetVO> getSaleSheetByState(SaleSheetState state) {
        // TODO
        // 根据单据状态获取销售单（注意：VO包含SaleSheetContent）
        // 依赖的dao层部分方法未提供，需要自己实现
        List<SaleSheetPO> saleSheetPOS = saleSheetDao.findSheetByState(state);
        List<SaleSheetVO> saleSheetVOS = new ArrayList<>();
        for (SaleSheetPO po : saleSheetPOS){
            SaleSheetVO vo = new SaleSheetVO();
            BeanUtils.copyProperties(po, vo);
            // set saleSheetContent
            List<SaleSheetContentPO> saleSheetContentPOS = saleSheetDao.findContentBySheetId(vo.getId());
            List<SaleSheetContentVO> saleSheetContentVOS = new ArrayList<>();
            for (SaleSheetContentPO ContentPO : saleSheetContentPOS){
                SaleSheetContentVO ContentVO = new SaleSheetContentVO();
                BeanUtils.copyProperties(ContentPO, ContentVO);
                saleSheetContentVOS.add(ContentVO);
            }
            vo.setSaleSheetContent(saleSheetContentVOS);
            saleSheetVOS.add(vo);
        }
        return saleSheetVOS;
    }

    /**
     * 根据销售单id进行审批(state == "待二级审批"/"审批完成"/"审批失败")
     * 在controller层进行权限控制
     *
     * @param saleSheetId 销售单id
     * @param state       销售单要达到的状态
     */
    @Override
    @Transactional
    public void approval(String saleSheetId, SaleSheetState state) {
        // TODO
        // 需要的service和dao层相关方法均已提供，可以不用自己再实现一遍
        /* 一些注意点：
            1. 二级审批成功之后需要进行
                 1. 修改单据状态
                 2. 更新商品表
                 3. 更新客户表
                 4. 新建出库草稿
            2. 一级审批状态不能直接到审批完成状态； 二级审批状态不能回到一级审批状态
         */
        if(state.equals(SaleSheetState.FAILURE)) {//目标状态: 审批失败
            if(saleSheetDao.findSheetById(saleSheetId).getState().equals(SaleSheetState.SUCCESS))
                throw new RuntimeException("该单据为审批成功单据");
            if(saleSheetDao.findSheetById(saleSheetId).getState().equals(SaleSheetState.FAILURE))
                throw new RuntimeException("该单据已经为审批失败单据");
            //update
            int is_update = saleSheetDao.updateSheetState(saleSheetId, state);
            if(is_update == 0) throw new RuntimeException("状态更新失败, 无匹配订单");
        } else if (state.equals(SaleSheetState.PENDING_LEVEL_1)) {//目标状态: 待一级审批状态
            if (saleSheetDao.findSheetById(saleSheetId).getState().equals(SaleSheetState.PENDING_LEVEL_2))
                throw new RuntimeException("二级审批不能回到一级审批");
            if (saleSheetDao.findSheetById(saleSheetId).getState().equals(SaleSheetState.PENDING_LEVEL_1))
                throw new RuntimeException("已经是待一级审批状态");
            if (saleSheetDao.findSheetById(saleSheetId).getState().equals(SaleSheetState.FAILURE))
                throw new RuntimeException("该单据为审批失败单据");
            if (saleSheetDao.findSheetById(saleSheetId).getState().equals(SaleSheetState.SUCCESS))
                throw new RuntimeException("该单据为审批成功单据");
        }else if (state.equals(SaleSheetState.PENDING_LEVEL_2)) {//目标状态: 待二级审批状态
            if (saleSheetDao.findSheetById(saleSheetId).getState().equals(SaleSheetState.PENDING_LEVEL_2))
                throw new RuntimeException("已经是待二级审批状态");
            if (saleSheetDao.findSheetById(saleSheetId).getState().equals(SaleSheetState.PENDING_LEVEL_1)) {
                //update
                int is_update = saleSheetDao.updateSheetState(saleSheetId, state);
                if (is_update == 0) throw new RuntimeException("状态更新失败, 无匹配订单");
            }
            if (saleSheetDao.findSheetById(saleSheetId).getState().equals(SaleSheetState.FAILURE))
                throw new RuntimeException("该单据为审批失败单据");
            if (saleSheetDao.findSheetById(saleSheetId).getState().equals(SaleSheetState.SUCCESS))
                throw new RuntimeException("该单据为审批成功单据");
        }else if (state.equals(SaleSheetState.SUCCESS)) {//目标状态: 审批成功
            if (saleSheetDao.findSheetById(saleSheetId).getState().equals(SaleSheetState.SUCCESS))
                throw new RuntimeException("已经是审批成功状态");
            if (saleSheetDao.findSheetById(saleSheetId).getState().equals(SaleSheetState.PENDING_LEVEL_2)) {
                //update
                int is_update = saleSheetDao.updateSheetState(saleSheetId, state);
                if (is_update == 0) throw new RuntimeException("状态更新失败, 无匹配订单");
                else {
                    //  审批完成, 修改一系列状态
                    // 更新商品表的最新进价
                    // 根据saleSheetId查到对应的content -> 得到商品id和单价
                    // 根据商品id和单价更新商品最近进价recentPp
                    List<SaleSheetContentPO> salseSheetContent = saleSheetDao.findContentBySheetId(saleSheetId);
                    List<WarehouseOutputFormContentVO> warehouseOutputFormContentVOS = new ArrayList<>();

                    for (SaleSheetContentPO content : salseSheetContent) {
                        ProductInfoVO productInfoVO = new ProductInfoVO();
                        productInfoVO.setId(content.getPid());
                        productInfoVO.setRecentRp(content.getUnitPrice());
                        productService.updateProduct(productInfoVO);

                        WarehouseOutputFormContentVO woContentVO = new WarehouseOutputFormContentVO();
                        woContentVO.setSalePrice(content.getUnitPrice());
                        woContentVO.setQuantity(content.getQuantity());
                        woContentVO.setRemark(content.getRemark());
                        woContentVO.setPid(content.getPid());
                        warehouseOutputFormContentVOS.add(woContentVO);
                    }
                    // 更新客户表(更新应付字段)
                    // 更新应付 payable
                    SaleSheetPO saleSheet = saleSheetDao.findSheetById(saleSheetId);
                    CustomerPO customerPO = customerService.findCustomerById(saleSheet.getSupplier());
                    customerPO.setReceivable(customerPO.getReceivable().add(saleSheet.getFinalAmount()));
                    customerService.updateCustomer(customerPO);

                    // 制定出库单草稿(在这里关联进货单)
                    // 调用创建出库单的方法
                    WarehouseOutputFormVO warehouseOutputFormVO = new WarehouseOutputFormVO();
                    warehouseOutputFormVO.setList(warehouseOutputFormContentVOS);
                    warehouseOutputFormVO.setSaleSheetId(saleSheetId);
                    warehouseService.productOutOfWarehouse(warehouseOutputFormVO);

                }
            }
            if (saleSheetDao.findSheetById(saleSheetId).getState().equals(SaleSheetState.FAILURE))
                throw new RuntimeException("该单据为审批失败单据");
            if (saleSheetDao.findSheetById(saleSheetId).getState().equals(SaleSheetState.PENDING_LEVEL_1))
                throw new RuntimeException("一级审批不能直接到达审批完成");
        }
    }

    /**
     * 获取某个销售人员某段时间内消费总金额最大的客户(不考虑退货情况,销售单不需要审批通过,如果这样的客户有多个，仅保留一个)
     * @param salesman 销售人员的名字
     * @param beginDateStr 开始时间字符串
     * @param endDateStr 结束时间字符串
     * @return
     */
    public CustomerPurchaseAmountPO getMaxAmountCustomerOfSalesmanByTime(String salesman,String beginDateStr,String endDateStr){
        DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try{
            Date beginTime =dateFormat.parse(beginDateStr);
            Date endTime=dateFormat.parse(endDateStr);
            if(beginTime.compareTo(endTime)>0){
                return null;
            }else{
                return saleSheetDao.getMaxAmountCustomerOfSalesmanByTime(salesman,beginTime,endTime);
            }
        }catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 根据销售单Id搜索销售单信息
     * @param saleSheetId 销售单Id
     * @return 销售单全部信息
     */
    @Override
    public SaleSheetVO getSaleSheetById(String saleSheetId) {
        SaleSheetPO saleSheetPO = saleSheetDao.findSheetById(saleSheetId);
        if(saleSheetPO == null) return null;
        List<SaleSheetContentPO> contentPO = saleSheetDao.findContentBySheetId(saleSheetId);
        SaleSheetVO sVO = new SaleSheetVO();
        BeanUtils.copyProperties(saleSheetPO, sVO);
        List<SaleSheetContentVO> saleSheetContentVOList = new ArrayList<>();
        for (SaleSheetContentPO content:
                contentPO) {
            SaleSheetContentVO sContentVO = new SaleSheetContentVO();
            BeanUtils.copyProperties(content, sContentVO);
            saleSheetContentVOList.add(sContentVO);
        }
        sVO.setSaleSheetContent(saleSheetContentVOList);
        return sVO;
    }

//   public List<SaleSpecificOutVO> getAllSaleDetailByTime(String beginDateStr, String endDateStr, String pName, String cName, String saleName){
//        return new ArrayList<>();
//   };

//    public List<businessConditionVO> getBusinessCondition(String beginDateStr, String endDateStr) throws ParseException{
//        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        String str1 = beginDateStr;
//        String str2=endDateStr;
//        Date date1 = simpleDateFormat.parse(str1);
//        Date date2 = simpleDateFormat.parse(str2);
//        int compareTo = date1.compareTo(date2);
//        if(compareTo>0) return null;
//        Timestamp timestamp1=new Timestamp(date1.getTime());
//        Timestamp timestamp2=new Timestamp(date2.getTime());
//
//        return saleSheetDao.getBusinessCondition(date1,date2);
//    };
public List<BusinessConditionVO> getBusinessCondition(String beginDateStr, String endDateStr) throws ParseException{
    //stub//
    List<BusinessConditionVO>businessConditionVOS=new ArrayList<>();
    BusinessConditionVO businessConditionVO=BusinessConditionVO.builder()
            .saleIn("15000.00")
            .goodIn("13000.00")

            .saleCost("2000.00")
            .goodCost("1000.00")
            .manCost("3000.00")
            .allowance("4000.00")
            .In1("24000.00")
            .Out1("6000.00")
            .profit("18000.00")
            .build();
    businessConditionVOS.add(businessConditionVO);
    return businessConditionVOS;
};


}
